﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ComputerArchitecture.Core;
using ComputerArchitecture.Core.Logging;
using ComputerArchitecture.Numbers;
using ComputerArchitecture.Units.Interfaces;

namespace ComputerArchitecture.Units.Complement
{
    public class ComplementAdderUnit : LoggingObject, IAdderUnit
    {
        #region Constructors

        public ComplementAdderUnit(ILoggingService loggingService) : base(loggingService)
        {
        }

        #endregion

        #region Methods
        
        private Bit FullAdder(Bit first, Bit second, Bit carryIn, out Bit carryOut)
        {
            ArgumentValidator.NullValidate(first);
            ArgumentValidator.NullValidate(second);
            ArgumentValidator.NullValidate(carryIn);
            Bit result = first.Xor(second).Xor(carryIn);
            carryOut = first.And(second).Xor(carryIn.And(first.Xor(second)));
            return result;
        }

        public ISignedBitNumber Add(ISignedBitNumber first, ISignedBitNumber second, out bool overflow)
        {
            ArgumentValidator.NullValidate(first);
            ArgumentValidator.NullValidate(second);
            if (first.Size != second.Size)
            {
                throw new ArgumentException();
            }
            this.LoggingService.LogInfo(string.Format("First number: {0:d4}", first));
            this.LoggingService.LogInfo(string.Format("Second number: {0:d4}", second));
            ISignedBitNumber result = new ComplementBitNumber(first.Size);
            Bit carryBit = Bit.Zero;
            for (int i = first.Size - 1, j = 1; i >= 0; i--, j++)
            {
                result[i] = this.FullAdder(first[i], second[i], carryBit, out carryBit);
                this.LoggingService.LogInfo(string.Format("Iteration {0}: result {1:d4}", j, result));
            }
            // if (all zeros and 1 overflow - ignore)
            // if carry from sign - ignore
            overflow = carryBit.IsSet;
            return result;
        }

        #endregion
    }
}
